<!--
 * @Author: fisher
 * @Date: 2023-12-29 09:34:04
 * @LastEditTime: 2023-12-29 19:49:04
 * @LastEditors: fisher
 * @Description: 
 * @FilePath: \front-end-template\src\modules\DataManage\transform\components\upload.vue
-->
<template>
  <div ref="upload" style="transition: 0.3s ease">
    <div class="upload_content" @drop="handleDrop" @dragover="handleDragOver">
      <div class="upload_slot">
        <div class="upload_btns">
          <div class="upload_btns_item" @click="previewResource">
            <img src="../asstes//imgs/file.webp" alt="浏览资源" />
            <span>浏览资源</span>
          </div>
          <div class="upload_btns_item">
            <img src="../asstes//imgs/upload.webp" alt="选择文件" />
            <span>选择文件</span>
            <input ref="inputArea" type="file" @change="fileChange" />
          </div>
        </div>
        <div class="upload_tips">
          点击上方“浏览资源、选择文件”或将文件拖拽到此区域
        </div>
      </div>
    </div>
    <div class="fileList">
      <div class="file_item" v-for="(item, index) in fileList" :key="index">
        <div class="file_content">
          <img
            style="width: 36px; height: 36px"
            src="../asstes/imgs/fileType.webp"
            alt="fileType"
          />
          <div
            style="
              display: flex;
              flex-direction: column;
              align-items: flex-start;
              flex: 1;
            "
          >
            <span style="font-size: 14px; font-weight: bold; color: #333">{{
              item.name
            }}</span>
            <span
              style="
                font-size: 14px;
                font-weight: bold;
                color: #333;
                opacity: 0.3;
              "
              >{{ item.size }} k</span
            >
          </div>
          <img
            style="
              width: 16px;
              height: 16px;
              cursor: pointer;
              margin-top: -10px;
            "
            src="../asstes/imgs/close.webp"
            alt="close"
            @click="deleteFile"
          />
        </div>
        <div class="upload_progress" v-if="showPercent">
          <fks-progress :percentage="percent"></fks-progress>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import SparkMD5 from "spark-md5";
import { uploadFile, mergeFile } from "./upload.js";
export default {
  //import引入组件才能使用
  components: {},
  props: {},
  data() {
    return {
      fileList: [],
      percent: 0, //上传比例
      showPercent: false, //显示上传比例进度
    };
  },
  // 计算属性
  computed: {},
  // 监听data中的数据变化
  watch: {},
  // 方法集合
  methods: {
    handleDrop(e) {
      e.preventDefault();
      const files = e.dataTransfer.files;
      console.log("handleDrop", files);
      //   清空上一个文件
      this.clearFileList();
      //   设置新的文件信息,这里不是实际上传
      this.setFileList(files[0]);
      //   这里是实际上传文件
      this.handleFileUpload(files[0]);
    },
    handleDragOver(e) {
      e.preventDefault();
      //   console.log("handleDragOver", e);
    },
    clearFileList() {
      this.$refs.upload.style.height = "200px";
      this.fileList = [];
    },
    setFileList(file) {
      this.$refs.upload.style.height = "330px";
      this.fileList.push({
        name: file.name,
        size: Math.ceil(file.size / 1024),
      });
    },
    deleteFile() {
      this.clearFileList();
    },
    previewResource() {},
    fileChange(e) {
      const files = e.target.files;
      //   清空上一个文件
      this.clearFileList();
      //   设置新的文件信息,这里不是实际上传
      this.setFileList(files[0]);
      this.handleFileUpload(files[0]);
    },
    handleFileUpload(file) {
      const startIndex = 0;
      this.showPercent = true;
      this.percent = 0;
      this.uploadFileSlice(file, startIndex, new Date().getTime());
    },
    async uploadFileSlice(file, startIndex, time) {
      const { name, size } = file;
      const unitSize = 1024 * 1024 * 5;
      const hash = await this.getMD5(file);
      const endIndex = Math.ceil(size / unitSize);
      // 如果 当前分片索引 大于 总分片数
      if (startIndex >= endIndex) {
        // 合并文件
        this.composeFile(name, size, endIndex, hash, time);
        return;
      }
      let uploadList = [];
      //  这段想表达的意思是将分片请求分组，如果总分片数小于5就按照总分片数设置请求数，如果大于5则每组按5个请求
      // 但是到最后一组会出现不足5的情况，最后一组按endIndex - startIndex计算，很混乱但是刚好能满足需求
      let requestNum = endIndex < 5 ? endIndex : 5;
      if (endIndex - startIndex < 5) {
        requestNum = endIndex - startIndex;
      }
      for (let i = 0; i < requestNum; i++) {
        const start = (startIndex + i) * unitSize;
        const end = Math.min(start + unitSize, size);
        // 切割文件
        const pak = file.slice(start, end);
        const formData = new FormData();
        formData.append("file", pak);
        formData.append("filename", name);
        formData.append("hash", time + "-" + name + "-" + (startIndex + i));
        uploadList.push(uploadFile(formData));
      }
      if (startIndex < endIndex) {
        Promise.all(
          uploadList.map((item) => {
            item.then((r) => {
              if (r.status) {
                startIndex++;
                this.percent = Math.floor((startIndex / endIndex) * 100);
                console.log("当前上传百分比 = ", this.percent);
              }
            });
            return item;
          })
        )
          .then(() => {
            this.uploadFileSlice(file, startIndex, time);
          })
          .catch((err) => {
            throw new Error(err);
          });
      }
    },
    getMD5(file) {
      return new Promise((resolve, reject) => {
        const spark = new SparkMD5.ArrayBuffer();
        // 获取文件二进制数据
        const fileReader = new FileReader();
        fileReader.readAsArrayBuffer(file); // file 就是获取到的文件
        // 异步执行函数
        fileReader.addEventListener("load", (e) => {
          spark.append(e.target.result);
          const md5 = spark.end();
          resolve(md5);
        });
        fileReader.addEventListener("error", (e) => {
          reject(e);
        });
      });
    },
    composeFile(name, size, endIndex, md5, time) {
      mergeFile({
        fileNum: endIndex,
        fileSize: size,
        filename: time + "-" + name,
        md5,
      }).then((res) => {
        console.log("后端接口合并文件 ===", res);
        this.percent = 100;
        this.$emit("updateTaskFile", {
          URI: res.data,
          fileName: name,
        });
        setTimeout(() => {
          this.showPercent = false;
          //   上传相同文件不响应bug修复
          this.$refs.inputArea.value = "";
        }, 500);
      });
    },
  },
  // 生命周期，创建完成时（可以访问当前this实例）
  created() {},
  // 生命周期：挂载完成时（可以访问DOM元素）
  mounted() {},
  beforeCreate() {}, //生命周期：创建之前
  beforeMount() {}, //生命周期：挂载之前
  beforeUpdate() {}, //生命周期：更新之前
  updated() {}, //生命周期：更新之后
  beforeDestroy() {}, //生命周期：销毁之前
  destroyed() {}, //生命周期：销毁完成
  activated() {}, //如果页面有keep-alive缓存功能，这个函数会触发执行
};
</script>
<style lang="scss" scoped>
.upload_content {
  width: 100%;
  height: 200px;
  border-radius: 5px;
  border: 1px dashed rgba($color: #000000, $alpha: 0.3);
  cursor: pointer;
  display: flex;
  justify-content: center;
  align-items: center;
}
.upload_content:hover {
  border: 1px dashed rgba($color: #1990ff, $alpha: 1);
  background: rgba($color: #1990ff, $alpha: 0.04);
}
.upload_slot {
  width: 50%;
  height: 60px;
  .upload_btns {
    display: flex;
    justify-content: space-between;
    .upload_btns_item {
      width: 46.7%;
      height: 36px;
      background-color: #1990ff;
      color: #fff;
      display: flex;
      justify-content: center;
      align-items: center;
      gap: 4px;
      border-radius: 2px;
      cursor: pointer;
      margin-bottom: 10px;
      position: relative;
      img {
        width: 18px;
        height: 18px;
        cursor: pointer;
      }
      input {
        position: absolute;
        width: 100%;
        height: 100%;
        opacity: 0;
        cursor: pointer;
      }
    }
  }
  .upload_tips {
    font-size: 12px;
    color: rgba($color: #000000, $alpha: 0.3);
    letter-spacing: 1.5px;
  }
}
.fileList {
  margin-top: 20px;
  display: flex;
  flex-direction: column;
  .file_item {
    width: 100%;
    height: 94px;
    padding: 0 25px;
    background: rgba($color: #1990ff, $alpha: 0.04);
    border-radius: 2px;
    box-shadow: 0 4px 10px 0 rgba($color: #000000, $alpha: 0.06);
    display: flex;
    flex-direction: column;
    // gap: 12px;
    .file_content {
      transition: 0.3s ease;
      display: flex;
      align-items: center;
      gap: 10px;
      flex: 1;
    }
    .upload_progress {
      margin-bottom: 20px;
    }
  }
}
</style>
